/*
 * @(#)Generate.java        0.1 09/04/29
 * @version 	0.1 29 Apr 2009
 * @author 	Do Van Khang
 * Hop thoai cung cap thong tin ve chuong tinh va nhom tac gia 
 */


package Generate;

import java.util.*;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class Generate {
	public static String newLine = System.getProperty("line.separator");
	public Generate() {
		
	}
	
	/*
	 * Sinh ma cho danh sach cac class
	 */
	public void GenerateCode(LinkedList<Data.Class> classes, File file) {
		try {
			for (int i = 0; i < classes.size(); i++) {
				File f = new File(file.getPath() + "/" + classes.get(i).getName() + ".java");
				FileWriter writer = new FileWriter(f);
				PrintWriter out = new PrintWriter(writer);
			    out.println(getCode(classes.get(i)));
			    out.close();
			}
		}
		catch (IOException e) {
		}

	}
	
	/*
	 * Luu ma 1 class vao file java tuong ung
	 */
	public void GenerateCode(Data.Class c, File file) {
		try {
				File f = new File(file.getPath() + "/" + c.getName() + ".java");
				FileWriter writer = new FileWriter(f);
				PrintWriter out = new PrintWriter(writer);
			    out.println(getCode(c));
			    out.close();
		}
		catch (IOException e) {
		}

	}
	
	/*
	 * Sinh ma 1 class
	 */
	public String getCode(Data.Class c) {
		String code = "";
		Calendar cal = Calendar.getInstance();
		DateFormat dateFormat = new SimpleDateFormat("yy/MM/dd");
		String date = dateFormat.format(cal.getTime());
		
		code += "/*" + newLine;
		code += " * @(#)" + c.getName() + ".java";
		code += "	" +date + newLine;
		code += " *" + newLine;
		code += " */" + newLine + newLine;
		
		if (c.getType() == Data.Class.CLASS) {
			code += "/*" + newLine;
			code += " *" + newLine;
			code += " */" + newLine;
		}
		// Lay visibility
		code += "public ";
		switch (c.getType()) {
		case Data.Class.CLASS:
			code += "class ";
			break;
		case Data.Class.ABSTRACT_CLASS:
			code += "abstract class ";
			break;
		case Data.Class.ENUM:
			code += "enum ";
			break;
		case Data.Class.INTERFACE:
			code += "interface ";
			break;
		}
		
		// Them ten class
		code += c.getName();
		
		// Tim cac lop co so hoac interface
		if (c.getType() == Data.Class.CLASS) {
			for (int i = 0; i < c.getBases().size(); i++) {
				if (c.getBases().get(i).getType() == Data.Class.CLASS || c.getBases().get(i).getType() == Data.Class.ABSTRACT_CLASS) {
					code += " extends " + c.getBases().get(i).getName();
				}
			}
			String implement = "";
			for (int i = 0; i < c.getBases().size(); i++) {
				if (c.getBases().get(i).getType() == Data.Class.INTERFACE) {
					implement += ", " + c.getBases().get(i).getName();
				}
			}
			if (!implement.equals("")) {
				implement = implement.substring(2);
				code += " implements " + implement;
			}
		}

		code += " {" + newLine;
		
		// Them ma cac attribute va method
		switch (c.getType()) {
		case Data.Class.CLASS:
			for (int i = 0; i < c.getAttributes().size(); i++) {
				code += "	//" + newLine;
				code += getAttributeCode(c.getAttributes().get(i));
				code += newLine;
			}
			code += newLine;
			for (int i = 0; i < c.getMethods().size(); i++) {
				code += "	/*" + newLine;
				code += "	 *" + newLine;
				code += "	 */" + newLine;
				code += getMethodCode(c.getMethods().get(i), false);
				code += " {";
				code += newLine + newLine;
				code += "	}";
				code += newLine + newLine;
			}
			for (int i = 0; i < c.getBases().size(); i++) {
				if (c.getBases().get(i).getType() == Data.Class.INTERFACE
						|| c.getBases().get(i).getType() == Data.Class.ABSTRACT_CLASS)
					for (int j = 0; j < c.getBases().get(i).getMethods().size(); j++) {
						code += "	/*" + newLine;
						code += "	 *" + newLine;
						code += "	 */" + newLine;
						System.out.print(code);
						code += getMethodCode(c.getBases().get(i).getMethods().get(j), false);
						code += " {";
						code += newLine + newLine;
						code += "	}";
						code += newLine + newLine;
					}
			}
			break;
		case Data.Class.ABSTRACT_CLASS:
			for (int i = 0; i < c.getAttributes().size(); i++) {
				code += getAttributeCode(c.getAttributes().get(i));
				code += newLine;
			}
			code += newLine;
			for (int i = 0; i < c.getMethods().size(); i++) {
				code += getMethodCode(c.getMethods().get(i), true);
				code += ';' + newLine + newLine;
			}
			break;
		case Data.Class.ENUM:
			for (int i = 0; i < c.getAttributes().size() - 1; i++) {
				code += c.getAttributes().get(i);
			}
			code += c.getAttributes().getLast() + ';';
			code += newLine;
			for (int i = 0; i < c.getMethods().size(); i++) {
				code += getMethodCode(c.getMethods().get(i), false);
				code += " {";
				code += newLine + newLine;
				code += "	}";
				code += newLine + newLine;
			}
			break;
		case Data.Class.INTERFACE:
			for (int i = 0; i < c.getMethods().size(); i++) {
				code += getMethodCode(c.getMethods().get(i), true);
				code += ';' + newLine + newLine;
			}
			break;
		}
		
		code += "}";
		return code;
	}
	
	/*
	 * Sinh ma 1 attribute
	 */
	public String getAttributeCode(String a) {
		String code = "	";
		String name = "";
		a = trim(a);
		String tmp[] = a.split(":");
		if (tmp.length != 2) return "";
		
		switch (tmp[0].charAt(0)) {
		case '+':
			code += "public ";
			name = tmp[0].substring(1);
			break;
		case '-':
			code += "private ";
			name = tmp[0].substring(1);
			break;
		case '#':
			code += "protected ";
			name = tmp[0].substring(1);
			break;
		default:
			name = tmp[0];
		}
		
		if (tmp[1].charAt(tmp[1].length() - 1) == ';') {
			code += tmp[1].substring(0, tmp[1].length() - 1);
		} else {
			code += tmp[1];
		}
		code += ' ' + name;
		code += ';';
		
		return code;
	}
	
	/*
	 * Sinh ma 1 method
	 */
	public String getMethodCode(String m, boolean isAbstract) {
		String code = "";
		code += "	";
		String param = "";
		m = trim(m);
		int pos = m.lastIndexOf(":");
		String tmp[] = new String[2];
		tmp[0] = m.substring(0, pos);
		tmp[1] = m.substring(pos + 1);
		
		switch (m.charAt(0)) {	
		case '+':
			code += "public ";
			tmp[0] = tmp[0].substring(1);
			break;
		case '-':
			code += "private ";
			tmp[0] = tmp[0].substring(1);
			break;
		case '#':
			code += "protected ";
			tmp[0] = tmp[0].substring(1);
			break;
		case '~':
			tmp[0] = tmp[0].substring(1);
		}
		
		if (isAbstract) {
			code += "abstract ";
		}
		
		if (tmp[1].charAt(tmp[1].length() - 1) == ';') {
			code += tmp[1].substring(0, tmp[1].length() - 1);
		} else {
			code += tmp[1];
		}
		
		pos = tmp[0].indexOf('(');
		int pos2 = tmp[0].indexOf(')');
		code += ' ' + tmp[0].substring(0, pos);
		code += '(';
		if (pos != -1 && pos2 != -1 && pos < pos2 - 1) {
			param = tmp[0].substring(pos + 1, pos2);
			LinkedList<String> params = getParams(param);
			for (int i = 0; i < params.size() - 1; i++) {
				code += params.get(i);
				code += ", ";
			}
			code += params.getLast();
		}
		code += ')';

		return code;
	}
	
	/*
	 * Sinh ma cho cac tham so
	 */
	public LinkedList<String> getParams(String p) {
		LinkedList<String> params = new LinkedList<String>();
		String tmp[] = p.split(",");
		for (int i = 0; i < tmp.length; i++) {
			String s[] = tmp[i].split(":");
			params.addLast(s[1] + ' ' + s[0]);
		}
		return params;
	}
	
	/*
	 * cat bo cac space
	 */
	private String trim(String s) {
		String tmp = "";
		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) != ' ') tmp += s.charAt(i);
		}
		return tmp;
	}
}